using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Office.Interop.Visio;
using System.Data;
using System.Data.OleDb;
using System.Collections;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Windows.Forms;
using Microsoft.Win32;
using visAd.ExceptionHandler;

using System.Web.Services.Protocols;
using System.Resources;
using System.Reflection;
using System.Configuration;
using visAd.Framework;



namespace visAd.ServerDataAddIn
{
    public class Utilities
    {
        private const string mClassName = "Utilities";
        private static ResourceManager resourceMgr = new ResourceManager("visAd.ServerDataAddIn.Properties.Resources", Assembly.GetExecutingAssembly());
        public static string AddinHelpFile = Utilities.AppPath() + "HelpFile\\Visio Add-In for System Center-User Guide.pdf";
            
        static internal string AppPath()
        {
            RegistryKey regKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Visio\Addins\visAd.ServerDataAddIn");
            string manifestLocation = string.Empty;
            if (regKey != null)
            {
                manifestLocation = regKey.GetValue("Manifest").ToString();
            }
            string directoryName = System.IO.Path.GetDirectoryName(manifestLocation);

            if (!directoryName.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString()))
            {
                directoryName += System.IO.Path.DirectorySeparatorChar.ToString();
            }

            // return result
            return directoryName;
        }

        /// <summary>
        /// This function splits the components of a marker event
        /// context string into parameters and values.        
        /// </summary>
        /// <param name="context">Context string from a marker event</param>
        /// <returns>Hashtable containing the parameters and values</returns>
        public static Hashtable ParseMarkerEventContext(string context)
        {
            Hashtable returnValue = new Hashtable();
            string[] argumentParts;
            try
            {
                if (context == null)
                    context = "";

                // The expected format for the persistent document event string looks like 
                // "/doc=1 /event=1 /eventid=1 /solution=VisioEPM /cmd=1"

                string[] contextParts = context.Trim().Split('/');

                int contextPartsLength = Convert.ToInt32(contextParts.Length);
                for (int contextPartIndex = 0; contextPartIndex < contextPartsLength; contextPartIndex++)
                {
                    string contextPart = contextParts[contextPartIndex].Trim();

                    if (contextPart.Length > 0)
                    {
                        // Separate the parameter from the parameter value.
                        argumentParts = contextPart.Split('=');
                        if (argumentParts.Length == 2)
                        {
                            returnValue.Add(argumentParts[0], argumentParts[1]);
                        }
                    }
                }
            }
            catch (Exception err)
            {
                ErrorLog.AddLogEntry(err, 1, true);
                throw;
            }
            return returnValue;

        }


        /// <summary>
        /// Get resource string from resource file
        /// </summary>
        /// <param name="resKey"></param>
        /// <returns></returns>
        public static string GetResourceString(string resKey)
        {
            try
            {
                return resourceMgr.GetString(resKey);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new vaCustomException(ex, mClassName, "GetResourceString");
            }
        }

        # region GetData

        /// <summary>
        /// This method will call the method GetData to get the control data for the passed node ids 
        /// </summary>
        /// <param name="filterXML">server filter</param>
        /// <returns></returns>
        public static DataSet GetServerDetails(XmlDocument filterXML)
        {
            //DataSet dsServerDetails = new DataSet();
            DataSet dsServerDetails = null;

            try
            {
                //visAd.ServerDataAddIn.SCConnectService.SCConnectService vaWS = new visAd.ServerDataAddIn.SCConnectService.SCConnectService();
                //vaWS.Credentials = System.Net.CredentialCache.DefaultCredentials;

                dsServerDetails = GetData(filterXML.OuterXml);
            }

            catch (vaCustomException vaEx)
            {
                // MessageBox.Show(vaEx.CustomMessage);
                vaEx.AddTrace(mClassName, "GetServerDetails");
                throw vaEx;
            }
            catch (Exception err)
            {
                ErrorLog.AddLogEntry(err, 2, true);
                // MessageBox.Show(err.Message);
                throw;
            }
            return dsServerDetails;
        }

      public static DataSet GetData(string filterXML)
      {
          try
          {
              ////get all the logging and exception info
              //IsFileLogRequired = (ConfigurationManager.AppSettings["FileLoggingRequired"].ToUpper() == "TRUE" ? true : false);
              //IsEventLogRequired = (ConfigurationManager.AppSettings["EventLoggingRequired"].ToUpper() == "TRUE" ? true : false);
              //LogDir = ConfigurationManager.AppSettings["ExceptioLogFile"];

              //Get server data from various servers
              XmlDocument xmlServerInfoFilter = new XmlDocument();
              xmlServerInfoFilter.LoadXml(filterXML);
              ServerFactory sf = new ServerFactory(xmlServerInfoFilter);
              return sf.CreateData();
          }

          catch (vaCustomException vaEx)
          {
              // MessageBox.Show(vaEx.CustomMessage);
              vaEx.AddTrace(mClassName, "GetData");
              throw vaEx;
          }
          catch (Exception)
          {
              // ErrorLog.AddLogEntry(err, 2, true);
              // MessageBox.Show(err.Message);
              throw;
          }
      }

      public static string GetDefaultServerList()
      {
          try
          {
              XmlDocument serverDetails = new XmlDocument();
              XmlDocument serverFields = new XmlDocument();
              // serverDetails.Load(@"C:\Connectors\Copy of System Center Without Web Service\SCOM_SCCM_Globalised_Code\visAd.ServerDataAddIn\XMLFile1.xml");
              //XmlDocument serverFields = new XmlDocument();
              XmlNodeList nodeList, fieldsList;
              ServerFactory sf;
              XmlNode filterNode;
              //get all the logging and exception info
              //IsFileLogRequired = (ConfigurationManager.AppSettings["FileLoggingRequired"].ToUpper() == "TRUE" ? true : false);
              //IsEventLogRequired = (ConfigurationManager.AppSettings["EventLoggingRequired"].ToUpper() == "TRUE" ? true : false);
              //LogDir = ConfigurationManager.AppSettings["ExceptioLogFile"];

              ConfigReader confReader = new ConfigReader();
              string serverList = confReader.GetDefaultServerFilterXML();
              if (String.IsNullOrEmpty(serverList))
              {
                  return String.Empty;
              }
              serverDetails.LoadXml(serverList);
              nodeList = serverDetails.SelectNodes("/visAd/va-servertype");
              sf = new ServerFactory();
              foreach (XmlNode node in nodeList)
              {
                  filterNode = serverDetails.CreateNode(XmlNodeType.Element, "va-filter", "");
                  node.AppendChild(filterNode);
                  serverFields.LoadXml(sf.GetFieldsData(node.Attributes.GetNamedItem("type").Value));
                  fieldsList = serverFields.SelectNodes("/configuration/va-servertype/va-field");
                  foreach (XmlNode field in fieldsList)
                  {

                      XmlNode newnode = serverDetails.ImportNode(field, true);
                      filterNode.AppendChild(newnode);
                      //serverDetails.InsertAfter(node.FirstChild, newnode);
                  }
              }
              return (serverDetails.OuterXml);
          }
          catch (vaCustomException vaEx)
          {
              // MessageBox.Show(vaEx.CustomMessage);
              vaEx.AddTrace(mClassName, "GetData");
              throw vaEx;
          }
          catch (Exception)
          {
              //ErrorLog.AddLogEntry(err, 2, true);
             // MessageBox.Show(err.Message);
              throw;
          }

      }
       
        public static XmlDocument GetServerDefaultXMLFilter()
        {
            try
            {
                //visAd.ServerDataAddIn.SCConnectService.SCConnectService vaWS = new visAd.ServerDataAddIn.SCConnectService.SCConnectService();
                //vaWS.Credentials = System.Net.CredentialCache.DefaultCredentials;
                XmlDocument serverFilter = new XmlDocument();

                string defaultserverfilter = GetDefaultServerList();
                if (String.IsNullOrEmpty(defaultserverfilter))
                {
                    return null;
                }
                serverFilter.LoadXml(defaultserverfilter);
                return (serverFilter);
            }
           
            catch (vaCustomException vaEx)
            {
              //  MessageBox.Show(vaEx.CustomMessage);
                vaEx.AddTrace(mClassName, "GetServerDefaultXMLFilter");
                throw vaEx;
            }
            catch (Exception err)
            {
                ErrorLog.AddLogEntry(err, 2, true);
             //   MessageBox.Show(err.Message);
                throw;
            }

        }
        #endregion

    
        /// <summary>
        /// This function returns the ADO classic  XML recordset representation
        /// of sourceDataTable. To acheive this, the function calls the
        /// ConvertToAdoRecordset function to convert the ADO.NET DataTable 
        /// into an ADO recordset. It then uses the ADO recordset's save
        /// method for XML persistance.
        /// </summary>
        /// <param name="dataTable">Reference to the ADO.NET 
        /// data table to convert</param>
        /// <returns>ADO classic  XML representation of the data contained 
        /// in sourceDataTable</returns>
        public static string ConvertAdoRecordsetToXML(System.Data.DataTable dataTable)
        {

            string strADOXMLString = "";
            ADODB.Recordset recordset;
            ADODB.StreamClass streamDOXML;

            try
            {
                recordset = new ADODB.RecordsetClass();
                streamDOXML = new ADODB.StreamClass();


                recordset = ConvertDataTableToDataRecordset(dataTable);
                recordset.Save(streamDOXML,
                    ADODB.PersistFormatEnum.adPersistXML);

                strADOXMLString = streamDOXML
                    .ReadText(streamDOXML.Size);
            }
            catch (Exception err)
            {
                ErrorLog.AddLogEntry(err, 1, true);
                throw;
            }
            return strADOXMLString;
        }

        /// <summary>
        /// This function converts the incoming ADO.NET sourceDataTable 
        /// to an ADO targetRecordset by: 
        /// 1.  Iterating first through the DataTable's DataColumns, converting 
        ///	 them to Fields &mapping their types by using the mapping 
        ///	 in the translateType function.
        /// 2.  Then populating the targetDataRecordset's rows by iterating through 
        ///	 and copying the value of the sourceDataTable's rows. 
        /// </summary>
        /// <param name="sourceDataTable">Reference to the ADO.NET data 
        /// table to convert</param>
        /// <returns>An ADO classic  DataRecordset representation of the data 
        /// contained in sourceDataTable</returns>
        public static ADODB.Recordset ConvertDataTableToDataRecordset(System.Data.DataTable sourceDataTable)
        {
            ADODB.Recordset targetRecordset = new ADODB.RecordsetClass();
            try
            {
                // Iterate through each DataColumn from the source data table
                // and create a new ADO field for each. 
                foreach (System.Data.DataColumn sourceColumn in sourceDataTable.Columns)
                {
                    // The targetRecordset.Fields.Append method requires
                    // a values for this attribute. 
                    ADODB.FieldAttributeEnum targetFieldAttribute;

                    if (sourceColumn.AllowDBNull)
                        targetFieldAttribute = ADODB.FieldAttributeEnum.adFldIsNullable;
                    else
                        targetFieldAttribute = ADODB.FieldAttributeEnum.adFldUnspecified;

                    targetRecordset.Fields.Append(sourceColumn.ColumnName, translateType(sourceColumn.DataType), sourceColumn.MaxLength, targetFieldAttribute, null);

                }
                // Open the recordset for input.
                targetRecordset.Open(
                    System.Reflection.Missing.Value,
                    System.Reflection.Missing.Value,
                    ADODB.CursorTypeEnum.adOpenStatic,
                    ADODB.LockTypeEnum.adLockOptimistic,
                    0);

                // For each row in the source DataTable, create a new recordset
                // row and copy entries to the newly created row.
                foreach (System.Data.DataRow sourceRow in sourceDataTable.Rows)
                {
                    targetRecordset.AddNew(
                        System.Reflection.Missing.Value,
                        System.Reflection.Missing.Value);

                    for (int i = 0; i < sourceDataTable.Columns.Count; i++)
                    {
                        targetRecordset.Fields[i].Value = sourceRow[i];
                    }

                }
            }
            catch (Exception err)
            {
                ErrorLog.AddLogEntry(err, 1, true);
                throw;
            }
            return targetRecordset;
        }

        /// <summary>
        /// This function converts ADO.NET data types to the nearest ADO 
        /// equivalents by using the UnderlyingSystemType method as
        /// a bridge.
        /// </summary>
        /// <param name="sourceColumnType">Type of the incoming ADO.NET 
        /// DataColumn</param>
        /// <returns>Equivalent ADO data type</returns>
        private static ADODB.DataTypeEnum translateType(System.Type sourceColumnType)
        {
            //ADODB.DataTypeEnum onErrorReturn = ADODB.DataTypeEnum.adIUnknown;
            try
            {

                switch (sourceColumnType.UnderlyingSystemType.ToString())
                {
                    case "System.Boolean":
                        return ADODB.DataTypeEnum.adBoolean;

                    case "System.Byte":
                        return ADODB.DataTypeEnum.adUnsignedTinyInt;

                    case "System.Char":
                        return ADODB.DataTypeEnum.adChar;

                    case "System.DateTime":
                        return ADODB.DataTypeEnum.adDate;

                    case "System.Decimal":
                        return ADODB.DataTypeEnum.adCurrency;

                    case "System.Double":
                        return ADODB.DataTypeEnum.adDouble;

                    case "System.Int16":
                        return ADODB.DataTypeEnum.adSmallInt;

                    case "System.Int32":
                        return ADODB.DataTypeEnum.adInteger;

                    case "System.Int64":
                        return ADODB.DataTypeEnum.adBigInt;

                    case "System.SByte":
                        return ADODB.DataTypeEnum.adTinyInt;

                    case "System.Single":
                        return ADODB.DataTypeEnum.adSingle;

                    case "System.UInt16":
                        return ADODB.DataTypeEnum.adUnsignedSmallInt;

                    case "System.UInt32":
                        return ADODB.DataTypeEnum.adUnsignedInt;

                    case "System.UInt64":
                        return ADODB.DataTypeEnum.adUnsignedBigInt;

                    case "System.String":
                        return ADODB.DataTypeEnum.adVarChar;

                    default:
                        return ADODB.DataTypeEnum.adVarChar;
                }
            }
            catch (Exception err)
            {
                ErrorLog.AddLogEntry(err, 1, true);
                throw;
            }
           // return onErrorReturn;
        }

        /// <summary>The FormulaStringToString method is used to format a Visio
        /// formula as a standard string.</summary>
        /// <remarks>The Visio Formula[U] methods return the formula as entered
        /// in the shapesheet.  Therefore, string formulas are wrapped in quote
        /// marks and an extra quote char is used when it is desired to place a
        /// quote character within a formula string.</remarks>
        /// <param name="formula">Value returned from a call to the Formula[U]
        /// methods of a cell</param>
        /// <returns>Converted string  (If an error occurs with the conversion,
        /// an empty string is returned.)</returns>
        public static string FormulaStringToString(string formula)
        {

            const string OneQuote = "\"";
            const string TwoQuotes = "\"\"";

            string convertedFormula = "";

            try
            {

                // Initialize the converted formula from the value passed in.
                convertedFormula = formula;

                // Check if this formula value is a quoted string.
                // If it is, remove extra quote characters.
                if (convertedFormula.StartsWith(OneQuote) &&
                    convertedFormula.EndsWith(OneQuote))
                {

                    // Remove the wrapping quote characters as well as any
                    // extra quote marks in the body of the string.
                    convertedFormula = convertedFormula.Substring(1,
                        (convertedFormula.Length - 2));
                    convertedFormula = convertedFormula.Replace(TwoQuotes,
                        OneQuote);
                }
            }

            catch (Exception err)
            {
                // Return a empty string if error occurs.
                convertedFormula = "";
                ErrorLog.AddLogEntry(err, 1, true);
            }
            return convertedFormula;
        }
        /// <summary>This method converts the input string to a Visio string by
        /// replacing each double quotation mark (") with a pair of
        /// double quotation marks ("") and then adding double quotation
        /// marks around the entire string.</summary>
        /// <param name="inputValue">Input string that will be converted
        /// to Visio string</param>
        /// <returns>A converted Visio string that can be programmatically assigned 
        /// to a ShapeSheet cell is returned.  Note that the string cannot be directly 
        /// pasted into a ShapeSheet cell because it doesn't have an "=" at its 
        /// beginning.</returns>
        public static string StringToFormulaForString(string inputValue)
        {
            string result = "";
            string quote = "\"";
            string quoteQuote = "\"\"";

            try
            {

                result = inputValue != null ? inputValue : String.Empty;

                // Replace all (") with ("").
                result = result.Replace(quote, quoteQuote);

                // Add ("") around the whole string.
                result = quote + result + quote;
            }
            catch (Exception err)
            {
                ErrorLog.AddLogEntry(err, 1, true);
            }

            return result;
        }
    }
}
